package system

import (
	"server/common/dto/response"
	"server/enumeration"
	"server/model"
	"server/repo"
	serviceRequest "server/service/dto/request"
	serviceResponse "server/service/dto/response"
	"server/utils"

	"github.com/thoas/go-funk"
)

type RoleService struct {
	Repository *repo.Repository[model.Role]
}

func NewRoleServiceApp(repository *repo.Repository[model.Role]) *RoleService {
	return &RoleService{
		Repository: repository,
	}
}

func roleNotFoundHandler() *response.ServiceError {
	return response.WrapError(
		response.RoleNotFoundCode,
		response.GetStatusCode(response.RoleNotFoundCode).Message,
	)
}

func roleExistsHandler() *response.ServiceError {
	return response.WrapError(
		response.RoleExistsCode,
		response.GetStatusCode(response.RoleExistsCode).Message,
	)
}

func (rs *RoleService) CreateRoleInfoService(requestData *serviceRequest.CreateRoleRequest) *response.ServiceError {
	var role model.Role
	if err := utils.ModelToStruct(&role, requestData); err != nil {
		return err
	}
	condition, err := utils.StructToMapWithoutZero(&requestData)
	if err != nil {
		return err
	}
	if !funk.IsEmpty(condition["description"]) {
		delete(condition, "description")
	}
	return rs.Repository.GenericCreateWithData(condition, &role, "OR", roleExistsHandler)
}

func (rs *RoleService) DeleteRoleInfoService(id string) (bool, *response.ServiceError) {
	return rs.Repository.GenericLogicDeleteById(id, "", roleNotFoundHandler)
}

func (rs *RoleService) ModifyRoleInfoSerice(requestData *serviceRequest.ModifyRoleRequest) (bool, *response.ServiceError) {
	return rs.Repository.GenericModifyByCondition(requestData.ID, &requestData, roleNotFoundHandler)
}

func (rs *RoleService) GetRoleInfoService(id string) (*serviceResponse.RoleResponse, *response.ServiceError) {
	role, err := rs.Repository.GenericQueryDetailById(id, roleNotFoundHandler)
	if err != nil {
		return nil, err
	}
	roleResponse, err := rs.buildResponseData(role)
	if err != nil {
		return nil, err
	}
	return roleResponse, nil
}

func (rs *RoleService) GetRoleListService(requestData *serviceRequest.RoleQueryRequest) (*[]serviceResponse.RoleResponse, *response.ServiceError) {
	condition, err := utils.StructToMapWithoutZero(requestData)
	if err != nil {
		return nil, err
	}
	roles, err := rs.Repository.GenericQueryListByCondition("", "", condition)
	if err != nil {
		return nil, err
	}
	roleListResponse, err := rs.buildResponseListData(roles)
	if err != nil {
		return nil, err
	}
	return roleListResponse, nil
}

func (rs *RoleService) GetRolePageService(requestData *serviceRequest.RoleQueryRequest) (*response.PageResponse[serviceResponse.RoleResponse], *response.ServiceError) {
	condition, err := utils.StructToMapWithoutZero(requestData)
	if err != nil {
		return nil, err
	}
	pageData, roles, err := rs.Repository.GenericQueryPageByCondition(requestData.Page, requestData.Size, "", "", condition)
	if err != nil {
		return nil, err
	}
	var pageResponse response.PageResponse[serviceResponse.RoleResponse]
	roleListResponse, err := rs.buildResponseListData(roles)
	if err != nil {
		return nil, err
	}
	pageResponse.Page = pageData.Page
	pageResponse.Size = pageData.Size
	pageResponse.Total = pageData.Total
	pageResponse.List = *roleListResponse

	return &pageResponse, nil
}

func (rs *RoleService) buildResponseData(role model.Role) (*serviceResponse.RoleResponse, *response.ServiceError) {
	var roleResponse serviceResponse.RoleResponse
	if err := utils.ModelToStruct(&roleResponse, role); err != nil {
		return nil, err
	}
	roleResponse.StatusName = enumeration.CommonStatus(role.Status).StatusString()
	return &roleResponse, nil
}

func (rs *RoleService) buildResponseListData(roles []model.Role) (*[]serviceResponse.RoleResponse, *response.ServiceError) {
	var roleListResponse []serviceResponse.RoleResponse
	for _, role := range roles {
		roleReponse, err := rs.buildResponseData(role)
		if err != nil {
			return nil, err
		}
		roleListResponse = append(roleListResponse, *roleReponse)
	}
	return &roleListResponse, nil
}
